package cn.tedu.charging.device.dao.repository;

import cn.tedu.charging.device.pojo.po.StationPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public abstract class AbstractStationCacheRepository {

    private static final String STATIONS_KEY = "stations_mapping";

    /**
     * 定义抽象方法
     * 子类来实现
     * 父类可以使用
     * @return
     */
    public abstract RedisTemplate getRedisTemplate();


    protected void saveLocationByGEOAndMemberIsId(List<StationPO> stations){

        GeoOperations geoOperations = getRedisTemplate().opsForGeo();
        //场站id和位置的映射
        Map<Integer, Point> idPointMap = new HashMap<>();
        //场站id和场站PO的映射
        Map<String, StationPO> idPOMap = new HashMap<>();
        stations.forEach(stationPO -> {
            //Point 是Spring-data-redis封装的一个对象 表示位置 一个点 入参是经纬度
            Point point = new Point(stationPO.getStationLng().doubleValue(),
                    stationPO.getStationLat().doubleValue());
            //一个一个的保存 不推荐
            //geoOperations.add("stations",point,stationPO);
            //member 不是stationPO 是 stationId

            idPointMap.put(stationPO.getId(),point);

        });
        //批量保存，
        //在操作数据库的时候，如果要保存多条数据，那么就可以使用批量操作，
        // 比如批量保存，批量删除，批量修改等。
        //封装的 GEOADD 这个命令
        geoOperations.add(STATIONS_KEY,idPointMap);
    }


    public List<StationPO> search(Double lng, Double lat, Integer distance) {
        GeoOperations geoOperations = getRedisTemplate().opsForGeo();

        //通过经纬度 创建一个 Point 对象
        Point point = new Point(lng,lat);
        //通过距离 设置 圆的半径 同时设置距离的单位 KILOMETERS
        //附近的充电站，附近的酒店 都是距离单位是 KILOMETERS
        //步行导航 附近的共享单车，共享充电宝 距离单位应该是 米
        Distance queryDistance = new Distance(distance, Metrics.KILOMETERS);
        //通过 点 和 半径 画个圆
        Circle circle = new Circle(point,queryDistance);

        RedisGeoCommands.GeoRadiusCommandArgs args =
                RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
        args.includeDistance().includeCoordinates();


        GeoResults<RedisGeoCommands.GeoLocation<Integer>> radius =
                geoOperations.radius(STATIONS_KEY, circle,args);
        List<StationPO> stationPOS = new ArrayList<>();

        for (GeoResult<RedisGeoCommands.GeoLocation<Integer>> result : radius) {
            //GeoResult 里的具体的数据 用 content 来表示
            RedisGeoCommands.GeoLocation<Integer> content = result.getContent();
            Distance resultDistance = result.getDistance();
            log.debug("距离:{}",resultDistance);
            //name 表示的是 GEOADD  是 member stationId
            Integer id = content.getName();
            StationPO stationPO = getStationById(id);
            stationPOS.add(stationPO);
        }
        return stationPOS;
    }

    /**
     * 定义抽象方法
     * 子类来实现
     * String opsForValue
     * Hash opsForHash
     * @param stationId
     * @return
     */
    public abstract StationPO getStationById(Integer stationId);

}
